package com.slipper.common.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.slipper.common.dao.CommonDao;
import com.slipper.core.transaction.ReadTransactional;
import com.slipper.core.transaction.WriteTransactional;
import com.slipper.exception.CommonException;
import com.slipper.mybatis.TriggerHelper;
import com.slipper.util.BeanUtil;
import com.slipper.util.DatabaseUtil;
import com.slipper.util.Tool;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@ReadTransactional
public class CommonService {
    @Resource
    private CommonDao commonDao;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void executeDDL(String sql) {
        if (Tool.isBlank()) throw new CommonException("ddl不能为空！");

        try {
            commonDao.executeSql(sql);
        } catch (Exception e) {
            throw new CommonException("执行ddl失败！", e);
        }
    }

    @WriteTransactional
    public int insert(Map<String, Object> paramMap) {
        return insert(paramMap, true);
    }

    @WriteTransactional
    public int insert(Map<String, Object> paramMap, boolean trigger) {
        try {
            TriggerHelper.setTrigger(trigger);
            return commonDao.insert(paramMap);
        } finally {
            TriggerHelper.setTrigger(false);
        }
    }

    @WriteTransactional
    public void insert(String tableName, Map<String, Object> data) {
        if (data.isEmpty()) return;

        String sql = "insert into " + wrapSymbol(tableName) + "(";
        sql += data.keySet().stream()
                .map(this::wrapSymbol)
                .collect(Collectors.joining(","));
        sql += ") values (";
        sql += data.keySet().stream()
                .map(field -> "#{" + field + "}")
                .collect(Collectors.joining(","));
        sql += ")";

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("sql", sql);
        paramMap.putAll(data);
        commonDao.insert(paramMap);
    }

    @WriteTransactional
    public int update(Map<String, Object> paramMap) {
        return update(paramMap, true);
    }

    @WriteTransactional
    public int update(Map<String, Object> paramMap, boolean trigger) {
        try {
            TriggerHelper.setTrigger(trigger);
            return commonDao.update(paramMap);
        } finally {
            TriggerHelper.setTrigger(false);
        }
    }

    @WriteTransactional
    public int delete(Map<String, Object> paramMap) {
        return delete(paramMap, true);
    }

    @WriteTransactional
    public int delete(Map<String, Object> paramMap, boolean trigger) {
        try {
            TriggerHelper.setTrigger(trigger);
            return commonDao.delete(paramMap);
        } finally {
            TriggerHelper.setTrigger(false);
        }
    }

    @WriteTransactional
    public int insert(List<Map<String, Object>> paramList) {
        return insert(paramList, true);
    }

    @WriteTransactional
    public int insert(List<Map<String, Object>> paramList, boolean trigger) {
        try {
            int result = 0;
            TriggerHelper.setTrigger(trigger);
            for (Map<String, Object> paramMap : paramList) {
                result += commonDao.insert(paramMap);
            }
            return result;
        } finally {
            TriggerHelper.setTrigger(false);
        }
    }

    @WriteTransactional
    public int update(List<Map<String, Object>> paramList) {
        return update(paramList, true);
    }

    @WriteTransactional
    public int update(List<Map<String, Object>> paramList, boolean trigger) {
        try {
            int result = 0;
            TriggerHelper.setTrigger(trigger);
            for (Map<String, Object> paramMap : paramList) {
                result += commonDao.update(paramMap);
            }
            return result;
        } finally {
            TriggerHelper.setTrigger(false);
        }
    }

    @WriteTransactional
    public int delete(List<Map<String, Object>> paramList) {
        int result = 0;
        for (Map<String, Object> paramMap : paramList) {
            result += commonDao.insert(paramMap);
        }
        return result;
    }

    @WriteTransactional
    public void batchInsert(String tableName, List<Map<String, Object>> dataList) {
        if (dataList.isEmpty()) return;
        for (Map<String, Object> data : dataList) {
            insert(tableName, data);
        }
    }

    @WriteTransactional
    public void batchUpdate(String tableName, String pkName, List<Map<String, Object>> dataList) {
        if (dataList.isEmpty()) return;

        for (Map<String, Object> data : dataList) {
            if (data.isEmpty()) return;

            String sql = "update " + wrapSymbol(tableName) + " set ";
            sql += data.keySet().stream()
                    .filter(item -> !item.equalsIgnoreCase(pkName))
                    .map(field -> wrapSymbol(field) + "=#{" + field + "}")
                    .collect(Collectors.joining(", "));
            sql += " where " + wrapSymbol(pkName) + "=#{" + pkName + "} ";

            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("sql", sql);
            paramMap.putAll(data);
            commonDao.update(paramMap);
        }
    }

    @WriteTransactional
    public int batchDelete(List<Map<String, Object>> paramList, boolean trigger) {
        try {
            int result = 0;
            TriggerHelper.setTrigger(trigger);
            for (Map<String, Object> paramMap : paramList) {
                result += commonDao.delete(paramMap);
            }
            return result;
        } finally {
            TriggerHelper.setTrigger(false);
        }
    }

    public int queryTotal(String sql) {
        return commonDao.queryTotal(new HashMap<>() {{
            put("sql", sql);
        }});
    }

    public int queryTotal(Map<String, Object> paramMap) {
        return commonDao.queryTotal(paramMap);
    }

    public Map<String, Object> queryOne(Map<String, Object> paramMap) {
        return BeanUtil.toLowerCaseKey(commonDao.queryOne(paramMap));
    }

    public List<Map<String, Object>> queryList(Map<String, Object> paramMap) {
        return BeanUtil.toLowerCaseKey(commonDao.queryList(paramMap));
    }

    public List<Map<String, Object>> queryList(String sql) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("sql", sql);
        return BeanUtil.toLowerCaseKey(commonDao.queryList(paramMap));
    }

    public PageInfo<Map<String, Object>> queryPage(int pageNumber, int pageSize, Map<String, Object> paramMap) {
        PageHelper.startPage(pageNumber, pageSize);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(commonDao.queryList(paramMap));
        pageInfo.setList(BeanUtil.toLowerCaseKey(pageInfo.getList()));
        return pageInfo;
    }

    public String wrapSymbol(String value) {
        return DatabaseUtil.wrapSymbol(value);
    }
}
